/*
 * @Author: Colin Dai
 * @Date: 2022-05-09 18:57:39
 * @LastEditors: Colin Dai
 * @LastEditTime: 2022-05-10 19:42:29
 * @FilePath: /jy-uos/src/softbus/discovery/discovery_service/source/discovery_service.c
 * @Description: 发现服务的处理
 * dailianzheng@163.com
 * Copyright (c) 2022 by Colin.Dai, All Rights Reserved. 
 */

#include "log.h"
#include "discovery_service.h"
#include "discovery_error.h"
#include "os_adapter.h"
#include "discovery_service_inner.h"
#include "bus_manager.h"
//安全内存处理需要
#include "securec.h"
#include <stdlib.h>
#include <string.h>

#ifdef COM_UDP
#include "udp_discovery_service.h"
#endif

/**
 * @brief 发布模块信息
 * @param {*}
 * @return {*}
 */
typedef struct {
    char package[MAX_PACKAGE_NAME];
    int publishId;
    unsigned short medium;
    unsigned short capabilityBitmap;
    unsigned short used;
} PublishModule;

#define MAX_MODULE_COUNT 3
//服务初始化标志
static int g_isServiceInit = 0;

//全局设备信息保存
static CommonDeviceInfo *g_deviceInfo = NULL;

static MutexId g_discoveryMutex = NULL;

//全局发布服务注册模块数组
PublishModule *g_publishModule = NULL;

//全局保存通道模式
ExchangeMedium g_exchangeMedium = UNDEF;


//函数前置声明
void PublishCallback(int publishId, int result,PublishModule *findModule, const IPublishCallback *cb);
int InitService(void);
PublishModule *AddPublishModule(const char *packageName, const PublishInfo *info);
PublishModule *FindExistModule(const char *packageName, int publishId);
PublishModule *FindFreeModule(void);
int InitCommonManager(void);
void DeinitCommonManager(void);
int InitLocalDeviceInfo(void);
int DiscoveryInit(void);
int DiscoveryDeinit(void);


/*** 
 * @brief 发布服务
 * @param {char} *moduleName
 * @param {PublishInfo*} info
 * @param {IPublishCallback} *cb
 * @return {*}
 */
int PublishService(const char *moduleName, const struct PublishInfo* info, const struct IPublishCallback *cb)
{
    //检查参数
    if (moduleName == NULL || strlen(moduleName) >= MAX_PACKAGE_NAME )
    {
        SOFTBUS_PRINT("[DISCOVERY] PublishService invliad para\n");
        PublishCallback(info->publishId, PUBLISH_FAIL_REASON_PARAMETER_INVALID, NULL, cb);
        return ERROR_INVALID;
    }  

    //TODO：目前只支持UDP方式，未来再支持其他模式再删除
    if (info->medium != UDP) {
        PublishCallback(info->publishId, PUBLISH_FAIL_REASON_NOT_SUPPORT_MEDIUM, NULL, cb);
        return ERROR_INVALID;
    }

    //处理通道模式,只使用第一次的模式，后续模式不同就报错
    if(UNDEF == g_exchangeMedium)
    {
        g_exchangeMedium = info->medium;
    }
    else
    {
         if(info->medium != g_exchangeMedium)
         {
            PublishCallback(info->publishId, PUBLISH_FAIL_REASON_NOT_SUPPORT_MEDIUM, NULL, cb);
            return ERROR_INVALID;
         }
    }

    if (g_discoveryMutex == NULL) {
        g_discoveryMutex = MutexInit();
        if (g_discoveryMutex == NULL) {
            PublishCallback(info->publishId, PUBLISH_FAIL_REASON_UNKNOWN, NULL, cb);
            return ERROR_FAIL;
        }
    }

    MutexLock(g_discoveryMutex);
    
    //启动服务
    if (InitService() != ERROR_SUCCESS) {
        SOFTBUS_PRINT("[DISCOVERY] PublishService InitService fail\n");
        PublishCallback(info->publishId, PUBLISH_FAIL_REASON_UNKNOWN, NULL, cb);
        MutexUnlock(g_discoveryMutex);
        return ERROR_FAIL;
    }
   

    //加入发布模块
    PublishModule *findModule = AddPublishModule(moduleName, info);
    if (findModule == NULL) {
        SOFTBUS_PRINT("[DISCOVERY] PublishService AddPublishModule fail\n");
        PublishCallback(info->publishId, PUBLISH_FAIL_REASON_UNKNOWN, NULL, cb);
        MutexUnlock(g_discoveryMutex);
        return ERROR_FAIL;
    }

    MutexUnlock(g_discoveryMutex);

   
    PublishCallback(info->publishId, ERROR_SUCCESS, findModule, cb);
    return ERROR_SUCCESS;
}

/*** 
 * @brief 取消服务
 * @param {char} *moduleName
 * @param {int} publishId
 * @return {*}
 */
int UnPublishService(const char *moduleName, int publishId)
{
    if (moduleName == NULL || publishId <= 0 || g_discoveryMutex == NULL) {
        SOFTBUS_PRINT("[DISCOVERY] UnPublishService invliad para\n");
        return ERROR_INVALID;
    }

    MutexLock(g_discoveryMutex);
    PublishModule *findModule = FindExistModule(moduleName, publishId);
    if (findModule == NULL) {
        SOFTBUS_PRINT("[DISCOVERY] UnPublishService get module fail\n");
        MutexUnlock(g_discoveryMutex);
        return ERROR_NONEXIST;
    }   

    memset_s(findModule, sizeof(PublishModule), 0, sizeof(PublishModule)); 

    MutexUnlock(g_discoveryMutex);
    SOFTBUS_PRINT("[DISCOVERY] UnPublishService ok\n");
    return ERROR_SUCCESS;

}


/**
 * @brief 发布回调
 * @param {int} publishId
 * @param {int} result
 * @param {PublishModule} *findModule
 * @param {IPublishCallback} *cb
 * @return {*}
 */
void PublishCallback(int publishId, int result,PublishModule *findModule, const IPublishCallback *cb)
{
    SOFTBUS_PRINT("[DISCOVERY] PublishCallback publishId=%d, result=%d\n", publishId, result);

    if (result == ERROR_SUCCESS) {
        if (cb->onPublishSuccess != NULL) {
            cb->onPublishSuccess(publishId);
        }
    } else {
        if (findModule != NULL) {            
            memset_s(findModule, sizeof(PublishModule), 0, sizeof(PublishModule));
        }

        if (cb->onPublishFail != NULL) {
            cb->onPublishFail(publishId, result);
        }
    }
}


/**
 * @brief 添加发布模块
 * @param {char} *packageName
 * @param {PublishInfo} *info
 * @return {*}
 */
PublishModule *AddPublishModule(const char *packageName, const PublishInfo *info)
{
    if (packageName == NULL || g_publishModule == NULL || info == NULL) {
        return NULL;
    }   

    if (FindExistModule(packageName, info->publishId) != NULL) {
        return NULL;
    }

    if (FindFreeModule() == NULL) {
        return NULL;
    }
    int ret;
    for (int i = 0; i < MAX_MODULE_COUNT; i++) {
        if (g_publishModule[i].used == 1) {
            continue;
        }      

        g_publishModule[i].capabilityBitmap = info->capability;

        g_publishModule[i].used = 1;      
      
        g_publishModule[i].medium = info->medium;
        g_publishModule[i].publishId = info->publishId;
        ret = memcpy_s(g_publishModule[i].package, MAX_PACKAGE_NAME, packageName, strlen(packageName));
        if (ret != 0) {          
            memset_s(&g_publishModule[i], sizeof(g_publishModule[i]), 0, sizeof(g_publishModule[i]));
            return NULL;
        }
        return &g_publishModule[i];
    }
    return NULL;
}


/**
 * @brief 搜索已经存在的模块
 * @param {char} *packageName
 * @param {int} publishId
 * @return {*}
 */
PublishModule *FindExistModule(const char *packageName, int publishId)
{
    if (packageName == NULL || g_publishModule == NULL) {
        return NULL;
    }

    for (int i = 0; i < MAX_MODULE_COUNT; i++) {
        if (g_publishModule[i].used == 0) {
            continue;
        }

        if (strcmp(g_publishModule[i].package, packageName) == 0 && g_publishModule[i].publishId == publishId) {
            return &g_publishModule[i];
        }
    }

    return NULL;
}


/**
 * @brief 是否所有模块空闲
 * @param {*}
 * @return {*}
 */
unsigned int IsAllModuleFree(void)
{
    if (g_publishModule == NULL) {
        return 1;
    }

    for (int i = 0; i < MAX_MODULE_COUNT; i++) {
        if (g_publishModule[i].used == 1) {
            return 0;
        }
    }

    return 1;
}


/**
 * @brief 搜索空闲模块
 * @param {*}
 * @return {*}
 */
PublishModule *FindFreeModule(void)
{
    if (g_publishModule == NULL) {
        return NULL;
    }

    for (int i = 0; i < MAX_MODULE_COUNT; i++) {
        if (g_publishModule[i].used == 1) {
            continue;
        }
        return &g_publishModule[i];
    }

    return NULL;
}




/**
 * @brief 去初始化服务
 * @param {*}
 * @return {*}
 */
int DeinitService(void)
{
    
    int ret = BusManager(0);
    if (ret != ERROR_SUCCESS) {
        SOFTBUS_PRINT("[DISCOVERY] DeinitService BusManager(0) fail\n");
    }

    if (g_publishModule) {
        free(g_publishModule);
        g_publishModule = NULL;
    }
 
    //去注册发现服务
    ret = DiscoveryDeinit();
    if (ret != ERROR_SUCCESS) {
        SOFTBUS_PRINT("[DISCOVERY] DeinitService CoapDeinit fail\n");
    }

    DeinitCommonManager();

    g_isServiceInit = 0;
    return ERROR_SUCCESS;
}

/**
 * @brief 初始化服务
 * @param {*}
 * @return {*}
 */
int InitService(void)
{
    if (g_isServiceInit != 0) {
        return ERROR_SUCCESS;
    }

    //初始化基本信息
    if (InitCommonManager() != 0) {
        SOFTBUS_PRINT("[DISCOVERY] InitService InitCommonManager fail\n");
        DeinitService();
        return ERROR_FAIL;
    }

    g_publishModule = calloc(1, sizeof(PublishModule) * MAX_MODULE_COUNT);
    if (g_publishModule == NULL) {
        DeinitService();
        return ERROR_NOMEMORY;
    }  
    
    //启动发现服务
    int ret = DiscoveryInit();
    if (ret != ERROR_SUCCESS) {
        SOFTBUS_PRINT("[DISCOVERY] InitService DiscoveryInit fail\n");
        DeinitService();
        return ret;
    }

    //启动总线服务
    ret = BusManager(1);
    if (ret != ERROR_SUCCESS) 
    {
        SOFTBUS_PRINT("[DISCOVERY] StartBusManager fail\n");
        return ret; 
    }
   
    g_isServiceInit = 1;
    SOFTBUS_PRINT("[DISCOVERY] InitService ok\n");
    return ERROR_SUCCESS;
}

/**
 * @brief 去初始化发现服务
 * @param {*}
 * @return {*}
 */
int DiscoveryDeinit(void)
{
    SOFTBUS_PRINT("[DISCOVERY] DiscoveryDeinit enter\n");


    int ret = ERROR_SUCCESS;

    #ifdef COM_UDP
    
    ret = UdpDiscoveryDeinit();

    #endif
    
    return ret;

}

/**
 * @brief 初始化发现服务
 * @param {*}
 * @return {*}
 */
int DiscoveryInit(void)
{
    SOFTBUS_PRINT("[DISCOVERY] DiscoveryInit enter\n");

    int ret = ERROR_SUCCESS;

    #ifdef COM_UDP
    
    ret = UdpDiscoveryInit();

    #endif
    
    return ret;
}


/**
 * @brief 初始化通用信息
 * @param {*}
 * @return {*}
 */
int InitCommonManager(void)
{
    if (InitLocalDeviceInfo() != 0) {
        SOFTBUS_PRINT("[DISCOVERY] InitCommonManager fail\n");
        return ERROR_FAIL;
    }
    return ERROR_SUCCESS;
}

/** 取消初始化基本信息
 * @brief 
 * @param {*}
 * @return {*}
 */
void DeinitCommonManager(void)
{
    if (g_deviceInfo != NULL) {
        free(g_deviceInfo);
        g_deviceInfo = NULL;
    }
}

int InitLocalDeviceInfo(void)
{

    if (g_deviceInfo != NULL) {
        memset_s(g_deviceInfo, sizeof(CommonDeviceInfo), 0, sizeof(CommonDeviceInfo));
    } else {
        g_deviceInfo = (CommonDeviceInfo *)calloc(1, sizeof(CommonDeviceInfo));
        if (g_deviceInfo == NULL) {
            return ERROR_FAIL;
        }
    }
    
    //TODO:需要考虑设备ID生产机制
    g_deviceInfo->deviceId = 1;

    g_deviceInfo->opt_devicePort = -1; 
    g_deviceInfo->deviceType = CUR_DEVICE_TYPE;
    g_deviceInfo->sdk_version = CUR_SDK_VERSION;   
    

    SOFTBUS_PRINT("[DISCOVERY] InitLocalDeviceInfo ok\n");
    return ERROR_SUCCESS;
}

/** 获取设备信息
 * @brief 
 * @param {*}
 * @return {*}
 */
CommonDeviceInfo *GetCommonDeviceInfo(void)
{
    return g_deviceInfo;
}

/**
 * @brief 获取通信通道信息
 * @param {*}
 * @return {*}
 */
ExchangeMedium GetExchangeMedium(void)
{
    return g_exchangeMedium;
}


